import redis
from flask_restful import Resource, fields, reqparse, abort, marshal

from main.apis.api_constant import HTTP_OK, USER_ACTION_REGISTER, HTTP_CREATE_OK, USER_ACTION_LOGIN, USER_ACTION_VERIFY, \
    USER_ACTION_LOGOUT, USER
from main.apis.utils import permission_required, check_user_exits, generate_verify_token, generate_user_token, \
    get_ordinary_user, check_email, clear_other_login_caches
from main.ext import cache
from main.models.admin.admin_model import PERMISSION_W
from main.models.goods.goods_model import Goods
from main.models.user.user_model import UsersModel
from main.apis.user.utils import send_mail


good_fields = {
    'name': fields.String(attribute='g_name'),
    'price': fields.Float(attribute='g_price'),
    'count': fields.Integer(attribute='g_count'),
}

good_status_fields = {
    'data': fields.Nested(good_fields),
    'status': fields.Integer,
    'msg': fields.String
}


class BuyResource(Resource):
    @permission_required(PERMISSION_W)
    def get(self, id, count=1):
        good = Goods.query.get(id)
        if not good:
            abort(404, error='未找到此商品')
        g_count = good.g_count
        if g_count == 0:
            abort(403, error='此商品已售完')
        if g_count < count:
            abort(403, error=f'商品库存不足，现有库存 -> {good.g_count} ')
        good.g_count = g_count - count
        if not good.save():
            abort(403, error='未能完成购买，请重试')
        data = {
            'status': HTTP_OK,
            'msg': '购买成功，库存减一',
            'data': good
        }

        return marshal(data, good_status_fields)


parser = reqparse.RequestParser()
# 根据三个参数的优先级来排序，最先判断的应该是请求参数，然后是用户名，最后是密码
parser.add_argument('action', type=str, required=True, help='请输入请求参数')

parser_register = parser.copy()
parser_register.add_argument('username', type=str, required=True, help='请输入用户名')
parser_register.add_argument('password', type=str, required=True, help='请输入密码')
parser_register.add_argument('email', type=str, required=True, help='请输入邮箱')
parser_register.add_argument('permission', type=int, help='请输入权限')

parser_login = parser.copy()
parser_login.add_argument('username', type=str, required=True, help='请输入用户名或邮箱')
parser_login.add_argument('password', type=str, required=True, help='请输入密码')

parser_logout = parser.copy()
parser_logout.add_argument('token', type=str, required=True, help='请输入当前登录用户的token')  # token在url中，也可以用request.args获取

parser_verify = parser.copy()
parser_verify.add_argument('token', type=str, required=True, help='请输入要验证用户的token')

user_fields = {
    'username': fields.String,
    'email': fields.String,
    'password': fields.String(attribute='_password')
}

single_user_data_fields = {
    'data': fields.Nested(user_fields),
    'status': fields.Integer,
    'msg': fields.String
}


class UsersResource(Resource):
    def get(self):
        args = parser.parse_args()
        action = args.get('action').lower()
        if action == USER_ACTION_VERIFY:
            args = parser_verify.parse_args()
            token = args.get('token')
            user_id = cache.get(token)
            cache.delete(token)
            if not user_id:
                # 如果顺利通过验证则无需提示直接跳转到登录页面
                abort(400, error='此验证链接已失效，可是能超过了5分钟或者已通过验证，如果你的账号尚未通过验证，请重新发送验证邮件')
            user = get_ordinary_user(user_id)
            if not user:
                abort(404, error='账户没有注册成功，请重新注册')
            if user.is_verify:
                abort(400, msg='您的邮箱已验证，请勿重复验证')
            user.is_verify = True
            if not user.save():
                abort(400, error='验证失败，请重新发送验证邮件进行验证')
            data = {
                'status': HTTP_OK,
                'msg': '验证成功',
                'data': user
            }

            return marshal(data, verify_data_fields)
        else:
            abort(404, error='非法的请求参数')

    def post(self):
        args = parser.parse_args()
        action = args.get('action').lower()
        if action == USER_ACTION_REGISTER:
            args = parser_register.parse_args()
            username = args.get('username')
            email = args.get('email')
            if not check_email(email):
                abort(403, error='邮箱格式错误，非正确邮箱将无法注册')
            password = args.get('password')
            if check_user_exits(username):
                abort(403, error='用户已存在！')
            if check_user_exits(email):
                abort(403, error='此邮箱已注册！')
            user = UsersModel()
            user.username = username
            user.email = email
            user.password = password
            if not user.save():
                abort(400, error='创建失败')
            # 生成用户注册验证用的token放到cache里，有效期5分钟，向邮箱中发送包含此token的验证链接，用户打开链接后，is_verify设置为True
            token = generate_verify_token()
            cache.set(token, user.id, timeout=60 * 5)
            """
            # 多线程发送验证邮件
            send_mail(email, token)
            """

            send_mail.delay(email, token)

            data = {
                'status': HTTP_CREATE_OK,
                'msg': '创建成功，已向您的邮箱发送了一封验证邮件，请及时验证',
                'data': user
            }

            return marshal(data, single_user_data_fields), HTTP_CREATE_OK  # 将要返回的状态码直接以数字作为return元组的第2个元素
        elif action == USER_ACTION_LOGIN:
            args_login = parser_login.parse_args()
            username_or_email = args_login.get('username')
            password = args_login.get('password')
            user = check_user_exits(username_or_email)
            if not user:
                abort(403, error='用户不存在')
            if user.is_delete:
                abort(403, error='用户已被删除')
            if not user.check_password(password):
                abort(401, error='用户名和密码不匹配')
            if not user.is_verify:
                token = generate_verify_token()
                cache.set(token, user.id, timeout=60 * 5)
                # send_mail(user.email, token)
                send_mail.delay(user.email, token)
                data = {
                    'status': HTTP_OK,
                    'msg': '您的邮箱尚未验证，现已发送验证邮件，请及时验证'
                }
                return data
            # 清除缓存中当前用户之前生成的登录token
            clear_other_login_caches(USER, user.id)
            # 生成用户登陆token放在cache里
            token = generate_user_token()
            cache.set(token, user.id, timeout=60 * 60 * 24)
            data = {
                'status': HTTP_OK,
                'msg': '已登录',
                'token': token
            }
            return data
        elif action == USER_ACTION_LOGOUT:
            args = parser_logout.parse_args()
            token = args.get('token')
            user_id = cache.get(token)
            if not user_id:
                abort(400, error='此用户已退出登录')
            user = UsersModel.query.get(user_id)
            if not user:
                abort(400, error=f'id为 -> {user_id} 的账号不存在或已被删除')
            cache.delete(token)

            data = {
                'status': HTTP_OK,
                'msg': f'用户 -> {user.username} 已退出登录'
            }

            return data
        else:
            abort(404, error='非法的请求')


verify_fields = {
    'username': fields.String,
    'email': fields.String,
    'is_verify': fields.String
}

verify_data_fields = {
    'data': fields.Nested(verify_fields),
    'status': fields.Integer,
    'msg': fields.String
}
